package com.lewei.open.distributed.lock.redis;

import com.lewei.open.distributed.lock.core.DistributedLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.concurrent.TimeUnit;

/**
 * {@link DistributedLock} by redis
 *
 * @author <a href="mailto:yins_emial@foxmail.com">yins</a>
 * @date 2021-11-08 18:01
 */
public class RedisDistributedLock implements DistributedLock<String> {

    private final RedisTemplate<String, String> redisTemplate;

    private final ValueOperations<String, String> ops;

    private final Logger log = LoggerFactory.getLogger(getClass());

    private static final String CONSTANTS_VALUE = "Redis_Distributed_Lock";

    public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.ops = redisTemplate.opsForValue();
        log.info("distributed lock by redis init success");
    }

    @Override
    public boolean lock(String key) {
        return acquiredLock(key);
    }

    @Override
    public boolean lock(String key, long duration, TimeUnit timeUnit) {
        return acquiredLock(key, duration, timeUnit);
    }

    @Override
    public void unlock(String key) {
        releaseLock(key);
    }

    /**
     * acquired Lock
     *
     * @param key redis lock of key
     */
    private boolean acquiredLock(String key) {
        return ops.setIfAbsent(key, CONSTANTS_VALUE);
    }

    /**
     * acquired Lock
     *
     * @param key      redis lock of key
     * @param l        duration
     * @param timeUnit {@link TimeUnit}
     */
    private boolean acquiredLock(String key, long l, TimeUnit timeUnit) {
        return ops.setIfAbsent(key, CONSTANTS_VALUE, l, timeUnit);
    }

    /**
     * release Lock
     *
     * @param key redis lock of key
     */
    private void releaseLock(String key) {
        redisTemplate.delete(key);
    }
}
